﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// 
    /// </summary>
    public class Median : BaseImageFilter
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Median"/> class.
        /// </summary>
        public Median()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Median"/> class.
        /// </summary>
        /// <param name="_median">The _median.</param>
        internal Median(Median _median)
        {
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap b = _bitmap;
            UnsafeBitmap b2 = (UnsafeBitmap)b.Clone();
            BitmapData bmData = b.BitmapData; //b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData bmData2 = b2.BitmapData; // b2.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = bmData.Stride;
            IntPtr Scan0 = bmData.Scan0;
            IntPtr Scan02 = bmData2.Scan0;

            unsafe
            {
                byte* p = (byte*)Scan0;
                byte* p2 = (byte*)Scan02;
                int nOffset = b.OffsetPointerIncrease; //stride - (b.Width * 3);
                int nByteCount = b.BytesPerPixelCount;
                int nWidth = b.Width * nByteCount; //b.Width * 3;
                p += stride;
                p2 += stride;
                for (int y = 1; y < (b.Height - 1); y++)
                {
                    p += nByteCount;
                    p2 += nByteCount;
                    for (int x = nByteCount; x < (nWidth - nByteCount); x++)
                    {
                        ArrayList list = new ArrayList();
                        list.Add(p2[0]);
                        list.Add(*(p2 - 3));            //list.Add(*(p2 - 3));

                        list.Add(p2[3]);                //list.Add(p2[3]);
                        list.Add(*(p2 - stride));
                        list.Add((p2 - stride)[3]);     //list.Add((p2 - stride)[3]);
                        list.Add(*((p2 - stride) - 3)); //list.Add(*((p2 - stride) - 3));
                        list.Add(p2[stride]);
                        list.Add((p2 + stride)[3]);     //list.Add((p2 + stride)[3]);
                        list.Add(*((p2 + stride) - 3)); //list.Add(*((p2 + stride) - 3));
                        list.Sort();
                        p[0] = (byte)list[4];
                        p++;
                        p2++;
                    }
                    p += nOffset + nByteCount;
                    p2 += nOffset + nByteCount;

                }
            }
            
            b2.Dispose(); //b2.UnlockBits(bmData2);
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Median(this);
        }
    }
}
